package org.jadapter.tests;

import static org.jadapter.tests.TestQuery.assertQueryEquals;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import junit.framework.TestCase;

import org.jadapter.Adapter;
import org.jadapter.JAdapter;
import org.jadapter.Query;
import org.jadapter.graph.TransitiveClosure;
import org.jadapter.registry.AdapterRegistry;
import org.jadapter.registry.TransitiveAdapterRegistry;
import org.jadapter.tests.examples.CommaSeparated;
import org.jadapter.tests.examples.ConstructorAdapter;
import org.jadapter.tests.examples.SortedMapList;
import org.junit.Test;



public class TestTransitivity extends TestCase {
    
    class A {} class B {} class C {} class D {}
    class X {} class Y {} class Z {}
    
    TransitiveClosure<Class<?>,Class<?>> graph;
    
    @Override
    public void setUp() {
        graph = new TransitiveClosure<Class<?>,Class<?>>(); 
    }
    
    public void testTo() {
        graph.insert(A.class,B.class,new Query<Class<?>>(X.class));
        Class<?> a = graph.to(B.class).iterator().next();
        assertEquals(A.class, a);
    }
    
    public void testFrom(){
        graph.insert(A.class,B.class,new Query<Class<?>>(X.class));
        Class<?> b = graph.from(A.class).iterator().next();
        assertEquals(B.class, b);        
    }

    
    public void testShouldNotContainDuplicates() {
        
        graph.insert(A.class,B.class, new Query<Class<?>>(X.class));
        assertEquals(1, graph.size());
        
        graph.insert(A.class,B.class, new Query<Class<?>>(X.class));
        assertEquals(1, graph.size());    
        
        graph.insert(C.class,D.class, new Query<Class<?>>(X.class));
        assertEquals(2, graph.size());    
    }
      
    
    public void testShouldReturnInsertedEdge(){
        graph.insert(B.class,A.class, new Query<Class<?>>(X.class));
        Query<Class<?>> edge = graph.get(B.class, A.class);
        assertNotNull(edge);
    }
    

    public void testShoulInferForwardRelationship(){
        graph.insert(A.class,B.class, new Query<Class<?>>(X.class));
        graph.insert(B.class,C.class, new Query<Class<?>>(Y.class));

        
        
        /*
         * X : A -> B
         * Y : B -> C
         * =>
         * XoY : A -> B -> C 
         */
        
        assertEquals(3, graph.size());  
        Query<Class<?>> query = graph.get(A.class, C.class);
        assertNotNull(query);
        
        assertQueryEquals(query, Y.class, X.class);
               
        graph.insert(C.class, D.class, new Query<Class<?>>(Z.class));
      
        assertQueryEquals(graph.get(A.class, D.class), Z.class, Y.class, X.class);     
        
    }
    
    
    public void testShouldInferBackwardRelationship(){
        graph.insert(B.class,C.class, new Query<Class<?>>(Y.class));
        graph.insert(A.class,B.class, new Query<Class<?>>(X.class));

        assertEquals(3, graph.size());  
        Query<Class<?>> query = graph.get(A.class, C.class);
        assertNotNull(query);
        
        assertQueryEquals(query, Y.class, X.class);
        
        
        graph.insert(C.class, D.class, new Query<Class<?>>(Z.class));
 
        
        assertQueryEquals(graph.get(A.class, D.class), Z.class, Y.class, X.class);          
        assertQueryEquals(graph.get(A.class, C.class), Y.class, X.class);          
        
    } 
    
    
    
    @Test public void testExplicitTransitivity() {
        
        Adapter<SortedMap,List> mapList = new SortedMapList();
        Adapter<CommaSeparated,Map> commaSeparatedMap = 
            new JAdapter(ConstructorAdapter.class)
                .to(CommaSeparated.class).from(Map.class);
        
        List<String> list = Arrays.asList("Foo", "Bar");
        
        Map map = mapList.transform(list);
        CommaSeparated commas = commaSeparatedMap.transform(map);
        
        assertEquals("0:Foo,1:Bar", commas.getCommaSeparated());  
    }
    

    @Test public void testImplicitTransitivity() {
        
        Adapter<SortedMap,List> mapList = new SortedMapList();
        Adapter<CommaSeparated,Map> commaSeparatedMap = 
            new JAdapter(ConstructorAdapter.class)
                .to(CommaSeparated.class).from(Map.class);
        
        // List -> SortedMap
        // List -> Map
        // Collection -> SortedMap 
        // Collection -> Map
        // Map -> CommaSeparated
        
        AdapterRegistry registry = new TransitiveAdapterRegistry(mapList, commaSeparatedMap);
        
        List<String> list = Arrays.asList("Foo", "Bar");
        
        CommaSeparated commas = registry.transform(list, CommaSeparated.class);
        
        assertEquals("0:Foo,1:Bar", commas.getCommaSeparated());  
    }
    
    
}
